//
//  IEnablerComms.m
//  Connect
//
//  Created by Daniel Lond on 29/07/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "IEnablerComms.h"


@implementation IEnablerComms

+(int)updateAccessTo:(bool) status forUser:(NSString*) usr withPwd:(NSString*) pwd {
	
	NSString * newStatus;
	NSString * exitMessage;
	
	if(status) {
		newStatus = @"1\r\n";
		exitMessage = @"User authorized";
	} else {
		newStatus = @"2\r\n";
		exitMessage = @"User was signed off";
	}
	
	//rw streams
	CFWriteStreamRef writeStream;
	CFReadStreamRef readStream;
	
	//CR-LF
	NSString * crlf = @"\r\n";
	
	//host
	CFHostRef host = CFHostCreateWithName(NULL, CFSTR("ienabler.canterbury.ac.nz"));
	SInt32 port = 259;
	
	//create streams
	CFStreamCreatePairWithSocketToCFHost(NULL, host, port, &readStream, &writeStream);
	
	//open streams
	NSLog(@"connecting ...\n");
	if(!CFReadStreamOpen(readStream)) {
		NSLog(@"error has occured opening read stream\n");
		return false;
	}
	
	if(!CFWriteStreamOpen(writeStream)) {
		NSLog(@"error has occured opening write stream\n");
		return false;
	}
	
	NSString * message = @"";
	bool done = false;
	UInt8 state = 0;
	while(!done){
		if(CFReadStreamHasBytesAvailable(readStream)) {
			UInt8 c[1];
			CFIndex bytesRead = CFReadStreamRead(readStream, c, 1);
			if(bytesRead < 0) {
				CFStreamError error = CFReadStreamGetError(readStream);
				if(error.domain == 1 && error.error == 54) {
					//connection reset by peer, this is a normal exit
					done = true;
				} else {
					NSLog(@"Read error: %d, %d", error.domain, error.error);
				}
			} else if(bytesRead == 0) {
				//stream doesn't end, just gets shut down (dom = 1, err = 54) but just in case ...
				if (CFReadStreamGetStatus(readStream) == kCFStreamStatusAtEnd) {
					done = true;
				}
			} else {
				message = [message stringByAppendingString:[[NSString alloc] initWithBytes:c length:1 encoding:1]];
			}
		} else {
			switch(state) {
				case 0: //Waiting for welcome
					
					if([message rangeOfString:@"Check Point"].location != NSNotFound) {
						//got welcome message, next state
						message = @"";
						state++;
					} else {
						//... keep waiting :/
					}
					break;
					
				case 1: //Submit usr+pwd
					
					[IEnablerComms myWrite:[usr stringByAppendingString:crlf] to:&writeStream];
					[IEnablerComms myWrite:[pwd stringByAppendingString:crlf] to:&writeStream];
					state++;
					break;
					
				case 2: //Waiting for usr+pwd accepted
					
					if([message rangeOfString:@"authenticated by Radius"].location != NSNotFound) {
						//received usr+pwd accepted, next state
						message = @"";
						state++;
					} else if([message rangeOfString:@"Access denied"].location != NSNotFound) {
						//bad usr+pwd :(
						return state;
					} else {
						//... keep waiting :/
						message = @"";
					}
					break;
					
				case 3: //Submit new status
					
					[IEnablerComms myWrite:newStatus to:&writeStream];
					state++;
					break;
					
				default: //Wait for exit message
					
					break;
			}
		}
	}
	
	CFReadStreamClose(readStream);
	CFWriteStreamClose(writeStream);
	CFRelease(readStream);
	CFRelease(writeStream);

	/*
	 We cannot check the exit status because the server closes the connection
	 before we finish reading
	*/

	return state;

   /*
   //Check exit message
   if([message rangeOfString:exitMessage].location != NSNotFound) {
		return true;
	} else {
		//didn't receive proper exit message ..?
		NSLog(@"Unexpected exit message: %@", message);
		return false;
	}
    */
}

+(void)myWrite:(NSString*) message to:(CFWriteStreamRef*) stream {
	UInt8 * buf = (UInt8 *)[message cStringUsingEncoding:1];
	CFIndex bufLen = strlen((const char *)buf);
	CFWriteStreamWrite(*stream, buf, bufLen);
}

@end
